/*
 * Copyright (c) 2008, University of Aarhus.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the name of the Univeristy of Aarhus nor the names
 *   of its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author: Morten Tranberg Hansen <mth@cs.au.dk>
 * @date:   May 8 2008	
 * 
 */

package dk.sensobyg.basestation;

import net.tinyos.message.*;
import java.util.List;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;

import java.io.IOException;

/**
 * The SensoByg BaseStation implementation.
 * 
 * @author Morten Tranberg Hansen (mth@daimi.au.dk)
 *
 */
@Deprecated
public class BaseStation implements MessageListener {    
    private static Logger log = Logger.getLogger("dk.sensobyg.basestation.BaseStation");
	
	private MoteIF mote;
    private Cache cache;
    LinkedList<Mote> motes;
    
    public BaseStation(Cache c) {
    	cache = c;
    	
    	mote = new MoteIF();//PrintStreamMessenger.err);
    	mote.registerListener(new SerialDataMessage(), this);
    	
    	motes = new LinkedList<Mote>();
    	log.info("BaseStation is up and running");
    }

    synchronized public void messageReceived(int dest_addr, Message message) {
    	if (message instanceof SerialDataMessage) {
    		SerialDataMessage dataMessage = (SerialDataMessage)message;
    		Mote mote = getMote(dataMessage.get_origin());
    		mote.newMessage(dataMessage);
    	}  
    }
    
    public void newData(DataItem item) {
    	//System.out.println(item);
    	try {
    		cache.addData(item);
    	} catch(CacheException e) {
    		log.error(e);
    	}
    }
    
    private Mote getMote(int moteid) {
    	for(Mote mote: motes) {
    		if(mote.getId()==moteid)
    			return mote;
    	}
    	Mote newMote = new Mote(this, moteid);
    	motes.add(newMote);
    	return newMote;
    }

	/**
	 * The method returns data related to a specific sensobyg sensor network. 
	 * The call is synchronous and can be called as often as wanted without 
	 * decreasing the lifetime of the network.
	 * The condition parameter is a comma seperated list of conditions that has 
	 * to be fulfilled by the data retrieved. 
	 * 
	 * <p>
	 * <b> Conditions </b>
	 * Each condition is on the form "data_field operator uint"
	 * <ul>
	 * <li> data_field: is either moteid, timestamp, or datatype. </li> 
	 * <li> operator: is either <, >, >=, <=, or = </li>
	 * <li> uint: is an unsigned integer representing the value a field is related to. </li>
	 * </ul> 
	 * </p>
	 * 
	 * <p>
	 * <b> Data field values </b>
	 * <ul> 
	 * <li> moteid: ranges from 0 to number of motes in the network </li>
	 * <li> timestamp: ranges from 0 to the current time in seconds since January 1, 1970, 00:00:00 GMT </li>
	 * <li> datatype: specificies the datatype of the data a record represents 
	 * (see constants from dk.sensobyg.basestation.Constants prefixed with SENSOBYG_DATA_TYPE) </li> 
	 * </ul>
	 * </p>
	 * 
	 * @param conditions A comma seperated of the list of conditions.
	 * @see dk.sensobyg.basestation.Types#DATA_TYPE_HUMIDITY  DATA_TYPE_HUMIDITY 
	 * @see dk.sensobyg.basestation.Types#DATA_TYPE_TEMPERATURE  DATA_TYPE_TEMPERATURE
	 * @return Possible empty list if data items.
	 * @throws IllegalArgumentException If the conditions can not be parsed. 
	 */
    public List<DataItem> getData(String conditions) throws IllegalArgumentException, CacheException {
    	StringTokenizer tokenizer = new StringTokenizer(conditions, ",");
    	Pattern pattern = Pattern.compile("(moteid|timestamp|datatype)(<|>|>=|<=|=)([0-9]+)");
    	while(tokenizer.hasMoreTokens()) {
    		String condition = tokenizer.nextToken();
    		Matcher m = pattern.matcher(condition);
    		if(!m.matches()) 
    			throw new IllegalArgumentException("The condition "+condition+" is not valid.");
    	}
    	return cache.getData(conditions);
    }
   
    /**
    * Get the IDs of all the motes the basestation has seen so far.
	* @return A list of mote IDs seen so far 
    */
    public List<Integer> getMotes() {
    	List<Integer> seen = new LinkedList<Integer>();
    	for(Mote mote : motes) {
    		seen.add(mote.getId());
    	}
    	return seen;
    }
    
	/**
	 * Configure the network through a command.
	 * @see dk.sensobyg.basestation.Command Command
	 * @param command The configuration command.
	 */
    public void command(Command command) {
    	CommandMessage message = new CommandMessage();
    	message.set_type(command.getType());
    	message.set_interval(command.getInterval());
    	message.set_target(command.getTarget());
    	message.amTypeSet(Constants.AM_SENSOBYG_COMMAND_MSG);
    	try {
    		mote.send(0/*MoteIF.TOS_BCAST_ADDR*/, message);
    	}
    	catch (IOException e) {
    		log.error("Cannot send configuration message to mote.");
    		log.debug(e);
    	}
    }
}
